package com.fl.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

/**
 * 
 * 加密帮助类<BR>
 * 
 * @author liangli
 * */
public class SecurityUtil {

	/**
	 * 获取大文件MD5码，不使用nio，防止后续文件锁住
	 * 
	 * @throws Exception
	 * */
	public static String MD5(File file) throws Exception {

		if (file == null || !file.exists() || !file.isFile()) {
			throw new Exception("MD5 file is null");
		}

		FileInputStream in = null;
		try {
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			in = new FileInputStream(file);
			// 开8M缓存
			byte[] buffer = new byte[8 * 1024];
			int length;
			while ((length = in.read(buffer)) != -1) {
				mdInst.update(buffer, 0, length);
			}

			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			return getHex(md);
		} catch (Exception e) {
			throw e;
		} finally {

			if (in != null) {
				in.close();
			}

		}
	}

	/**
	 * 获取字符串MD5码
	 * 
	 * @throws Exception
	 * */
	public static String MD5(String s) throws Exception {

		if (StringUtil.isBlank(s)) {
			throw new Exception("MD5 String is null");
		}

		byte[] btInput = s.getBytes();
		// 获得MD5摘要算法的 MessageDigest 对象
		MessageDigest mdInst = MessageDigest.getInstance("MD5");
		// 使用指定的字节更新摘要
		mdInst.update(btInput);
		// 获得密文
		byte[] md = mdInst.digest();
		// 把密文转换成十六进制的字符串形式
		return getHex(md);
	}

	/**
	 * 转换byte数组为16进制码
	 * */
	private static String getHex(byte[] content) {

		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };

		// 把密文转换成十六进制的字符串形式
		int j = content.length;
		char str[] = new char[j * 2];
		int k = 0;
		for (int i = 0; i < j; i++) {
			byte byte0 = content[i];
			str[k++] = hexDigits[byte0 >>> 4 & 0xf];
			str[k++] = hexDigits[byte0 & 0xf];
		}
		return new String(str);

	}

	public static void desEncrypt(String key, String source, String dest)
			throws Exception {
		
		if(StringUtil.isBlank(key)){
			throw new Exception("DES Key is null");
		}
		
		if(StringUtil.isBlank(source)){
			throw new Exception("DES Source File is null");
		}
		File file = new File(source);
		if(!file.exists()){
			throw new Exception("DES Source File is not exists");
		}
		
		if(!file.isFile()){
			throw new Exception("DES Source File is not a file");
		}
		
		des(Cipher.ENCRYPT_MODE, key, new FileInputStream(source),
				new FileOutputStream(dest));
	}

	public static void desDecrypt(String key, String source, String dest)
			throws Exception {
		
		if(StringUtil.isBlank(key)){
			throw new Exception("DES Key is null");
		}
		
		if(StringUtil.isBlank(source)){
			throw new Exception("DES Source File is null");
		}
		File file = new File(source);
		if(!file.exists()){
			throw new Exception("DES Source File is not exists");
		}
		
		if(!file.isFile()){
			throw new Exception("DES Source File is not a file");
		}
		
		des(Cipher.DECRYPT_MODE, key, new FileInputStream(source),
				new FileOutputStream(dest));
	}

	private static void des(int mode, String key, InputStream is,
			OutputStream os) throws Exception {

		DESKeySpec dks = new DESKeySpec(key.getBytes());
		SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
		SecretKey desKey = skf.generateSecret(dks);
		Cipher cipher = Cipher.getInstance("DES"); // DES/ECB/PKCS5Padding for
													// SunJCE

		if (mode == Cipher.ENCRYPT_MODE) {
			cipher.init(Cipher.ENCRYPT_MODE, desKey);
			CipherInputStream cis = new CipherInputStream(is, cipher);
			doCopy(cis, os);
		} else if (mode == Cipher.DECRYPT_MODE) {
			cipher.init(Cipher.DECRYPT_MODE, desKey);
			CipherOutputStream cos = new CipherOutputStream(os, cipher);
			doCopy(is, cos);
		}
	}

	private static void doCopy(InputStream is, OutputStream os)
			throws IOException {
		// 开8M缓存
		byte[] bytes = new byte[8 * 1024];
		int numBytes;
		while ((numBytes = is.read(bytes)) != -1) {
			os.write(bytes, 0, numBytes);
		}
		os.flush();
		os.close();
		is.close();
	}

}
